from sqlite_utils import Database


def test_tracer():
    collected = []
    db = Database(
        memory=True, tracer=lambda sql, params: collected.append((sql, params))
    )
    dogs = db.table("dogs")
    dogs.insert({"name": "Cleopaws"})
    dogs.enable_fts(["name"])
    dogs.search("Cleopaws")
    assert collected == [
        ("PRAGMA recursive_triggers=on;", None),
        ("select name from sqlite_master where type = 'view'", None),
        ("select name from sqlite_master where type = 'table'", None),
        ("select name from sqlite_master where type = 'view'", None),
        ("select name from sqlite_master where type = 'view'", None),
        ("select name from sqlite_master where type = 'table'", None),
        ("select name from sqlite_master where type = 'view'", None),
        ('CREATE TABLE "dogs" (\n   "name" TEXT\n);\n        ', None),
        ("select name from sqlite_master where type = 'view'", None),
        ('INSERT INTO "dogs" ("name") VALUES (?)', ["Cleopaws"]),
        (
            'CREATE VIRTUAL TABLE "dogs_fts" USING FTS5 (\n    "name",\n    content="dogs"\n)',
            None,
        ),
        (
            'INSERT INTO "dogs_fts" (rowid, "name")\n    SELECT rowid, "name" FROM "dogs";',
            None,
        ),
    ]


def test_with_tracer():
    collected = []

    def tracer(sql, params):
        return collected.append((sql, params))

    db = Database(memory=True)

    dogs = db.table("dogs")

    dogs.insert({"name": "Cleopaws"})
    dogs.enable_fts(["name"])

    assert len(collected) == 0

    with db.tracer(tracer):
        list(dogs.search("Cleopaws"))

    assert len(collected) == 5
    assert collected == [
        (
            "SELECT name FROM sqlite_master\n"
            "    WHERE rootpage = 0\n"
            "    AND (\n"
            "        sql LIKE :like\n"
            "        OR sql LIKE :like2\n"
            "        OR (\n"
            "            tbl_name = :table\n"
            "            AND sql LIKE '%VIRTUAL TABLE%USING FTS%'\n"
            "        )\n"
            "    )",
            {
                "like": '%VIRTUAL TABLE%USING FTS%content="dogs"%',
                "like2": '%VIRTUAL TABLE%USING FTS%content="dogs"%',
                "table": "dogs",
            },
        ),
        ("select name from sqlite_master where type = 'view'", None),
        ("select name from sqlite_master where type = 'view'", None),
        ("select sql from sqlite_master where name = ?", ("dogs_fts",)),
        (
            'with "original" as (\n'
            "    select\n"
            "        rowid,\n"
            "        *\n"
            '    from "dogs"\n'
            ")\n"
            "select\n"
            '    "original".*\n'
            "from\n"
            '    "original"\n'
            '    join "dogs_fts" on "original".rowid = "dogs_fts".rowid\n'
            "where\n"
            '    "dogs_fts" match :query\n'
            "order by\n"
            '    "dogs_fts".rank',
            {"query": "Cleopaws"},
        ),
    ]

    # Outside the with block collected should not be appended to
    dogs.insert({"name": "Cleopaws"})
    assert len(collected) == 5
